﻿using System;
using System.Collections.Generic;
using System.Data;
using JTLeigh.Commerce.Spencer.Core.Common;
using JTLeigh.Commerce.Spencer.Core.Common.Services;
using JTLeigh.Commerce.Spencer.Core.Data.Services;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities;
using Microsoft.Practices.Unity;
using ProductFeedbackE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedback;

namespace JTLeigh.Commerce.Spencer.Features.ProductFeedback.Data.Providers
{

	/// <summary>
	/// An <see cref="IProductFeedbackProvider"/> implementation that retrieves product feedback 
	/// from the database.
	/// </summary>
	public class ProductFeedbackProvider : IProductFeedbackProvider
	{

		#region Inner Classes and Types

		internal static class StoredProcedure
		{

			public static class GetProductFeedback
			{

				public const string CommandName = "GetProductFeedback";

				public static class ParameterName
				{
					public const string TenantId = "@TenantId";
                    public const string CatalogId = "@CatalogId";
                    public const string ProductId = "@ProductId";
                }

				public static class ColumnName
				{

                    public static class ProductFeedback
                    {
                        public const string FeedbackId = "FeedbackId";
                        public const string CultureId = "CultureId";
                        public const string DateAdded = "DateAdded";
                        public const string CustomerId = "CustomerId";
                        public const string CustomerName = "CustomerName";
                        public const string CustomerLocation = "CustomerLocation";
                        public const string EditorComments = "EditorComments";
                    }

                    public static class ProductFeedbackBadgeAssociation
                    {
                        public const string BadgeId = "BadgeId";
                    }

                    public static class ProductRating
					{
						public const string Value = "Value";
					}

					public static class ProductRatingAttributeValue
					{
						public const string AttributeId = "AttributeId";
						public const string Value = "Value";
					}

					public static class ProductRecommendation
					{
						public const string Value = "Value";
					}

					public static class ProductRecommendationAttributeValue
					{
						public const string AttributeId = "AttributeId";
						public const string Value = "Value";
					}

					public static class ProductReview
					{
						public const string Title = "Title";
						public const string Body = "Body";
					}

					public static class ProductReviewAttributeValue
					{
						public const string AttributeId = "AttributeId";
						public const string Value = "Value";
					}

                    public static class ProductReviewImage
                    {
                        public const string ImageId = "ImageId";
                        public const string Caption = "Caption";
                        public const string ThumbnailPath = "ThumbnailPath";
                        public const string ThumbnailWidth = "ThumbnailWidth";
                        public const string ThumbnailHeight = "ThumbnailHeight";
                        public const string ImagePath = "ImagePath";
                        public const string ImageWidth = "ImageWidth";
                        public const string ImageHeight = "ImageHeight";
                    }

                    public static class ProductReviewVideo
                    {
                        public const string StillPath = "StillPath";
                        public const string StillWidth = "StillWidth";
                        public const string StillHeight = "StillHeight";
                        public const string VideoPath = "VideoPath";
                        public const string VideoWidth = "VideoWidth";
                        public const string VideoHeight = "VideoHeight";
                        public const string Length = "Length";
                        public const string Transcript = "Transcript";
                    }

                    public static class ProductReviewThirdPartyRatingCounts
					{
						public const string TotalThirdPartyReviews = "TotalThirdPartyReviews";
						public const string PositiveThirdPartyReviews = "PositiveThirdPartyReviews";
					}

				}

			}

		}

		#endregion // Inner Classes and Types

		#region Constants

		/// <summary>
		/// The database key to use to create database connections for performing read operations.
		/// </summary>
		protected internal const string DatabaseKeyReadOperations = "ProductFeedbackReadOperations";

		/// <summary>
		/// The schema name to qualify commands with.
		/// </summary>
		protected internal const string DatabaseSchema = "ProductFeedback";

		#endregion // Constants

		#region Properties

		/// <summary>
		/// Gets or sets the database connection factory to use to create connections to databases.
		/// </summary>
		/// <value>An <see cref="IDatabaseConnectionFactory"/> implementation.</value>
		[Dependency]
		public IDatabaseConnectionFactory DatabaseConnectionFactory { get; set; }

		/// <summary>
		/// Gets or sets the exception handling service to use to handle exceptions.
		/// </summary>
		/// <value>An <see cref="IExceptionHandlingService"/> implementation.</value>
		[Dependency]
		public IExceptionHandlingService ExceptionHandlingService { get; set; }

		#endregion // Properties

		#region IProductFeedbackProvider Members

		/// <summary>
		/// Gets a dictionary of product feedback by product identifier.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant whose
		/// product feedback is to be retrieved.</param>
        /// <param name="catalogId">The catalog identifier <see cref="String"/> of the catalog
        /// that the product whose product feedback is to be retrieved is in.</param>
        /// <param name="productId">The product identifier <see cref="String"/> of the product 
		/// whose product feedback is to be retrieved.</param>
		/// <returns>A <see cref="Dictionary{TKey,TValue}"/> of <see cref="ProductFeedbackE"/> 
		/// keyed by feedback identifier <see cref="Guid"/>.</returns>
		public Dictionary<Guid, ProductFeedbackE> GetProductFeedback(Guid tenantId, string catalogId, string productId)
		{
			IDbCommand command;
			Dictionary<Guid, ProductFeedbackE> feedbackCollection;

            Safety.AssertArgumentNotNull("catalogId", catalogId);
            Safety.AssertArgumentNotNull("productId", productId);

			try
			{
				using (IDbConnection connection = CreateDatabaseConnectionReadOperations(tenantId, catalogId, productId))
				{
					connection.Open();
					try
					{
						using (command = CreateGetProductFeedbackCommand(connection, tenantId, catalogId, productId))
						{
							feedbackCollection = ReadProductFeedback(command);
						}
						return feedbackCollection;
					}
					finally
					{
						connection.Close();
					}
				}
			}
			catch (Exception e)
			{
				ExceptionHandlingService.HandleException(tenantId, e, ProductFeedbackExceptionPolicy.Data);
				throw;
			}
		}

		#endregion // IProductFeedbackProvider Members

		#region Implementation

		/// <summary>
		/// Creates a connection to the database to be used for performing read operations.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant who the
		/// database connection is being created for.</param>
        /// <param name="catalogId">The catalog identifier <see cref="String"/> of the catalog
        /// that the database connection is being created for.</param>
        /// <param name="productId">The product identifier <see cref="String"/> of the product that
		/// the database connection is being created for.</param>
		/// <returns>An <see cref="IDbConnection"/> connection to the specified database.</returns>
		protected virtual IDbConnection CreateDatabaseConnectionReadOperations(Guid tenantId, string catalogId, string productId)
		{
			return DatabaseConnectionFactory.CreateDatabaseConnection(tenantId, DatabaseKeyReadOperations);
		}

		/// <summary>
		/// Gets the fully-qualified command name.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant who the
		/// command name is being qualified for.</param>
		/// <param name="commandName">The command name to qualify.</param>
		/// <returns>The fully-qualified command name.</returns>
		protected virtual string GetFullyQualifiedCommandName(Guid tenantId, string commandName)
		{
			return String.Concat("[", DatabaseSchema, "].[", commandName, "]");
		}

		#region GetProductFeedback

		private IDbCommand CreateGetProductFeedbackCommand(IDbConnection connection, Guid tenantId, string catalogId, string productId)
		{
			IDbCommand command;
			IDbDataParameter parameter;

			Safety.AssertArgumentNotNull("connection", connection);
            Safety.AssertArgumentNotNull("catalogId", catalogId);
            Safety.AssertArgumentNotNull("productId", productId);

			command = connection.CreateCommand();
			command.CommandText = GetFullyQualifiedCommandName(tenantId, StoredProcedure.GetProductFeedback.CommandName);
			command.CommandType = CommandType.StoredProcedure;

			parameter = command.CreateParameter();
			parameter.ParameterName = StoredProcedure.GetProductFeedback.ParameterName.TenantId;
			parameter.Value = tenantId;
			command.Parameters.Add(parameter);

            parameter = command.CreateParameter();
            parameter.ParameterName = StoredProcedure.GetProductFeedback.ParameterName.CatalogId;
            parameter.Value = catalogId;
            command.Parameters.Add(parameter);

			parameter = command.CreateParameter();
			parameter.ParameterName = StoredProcedure.GetProductFeedback.ParameterName.ProductId;
			parameter.Value = productId;
			command.Parameters.Add(parameter);

			return command;
		}

		private static Dictionary<Guid, ProductFeedbackE> ReadProductFeedback(IDbCommand command)
		{
			Dictionary<Guid, ProductFeedbackE> feedbackCollection;

			Safety.AssertArgumentNotNull("command", command);

			feedbackCollection = new Dictionary<Guid, ProductFeedbackE>();
			using (IDataReader reader = command.ExecuteReader())
			{
				try
				{
					ReadProductFeedback(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 1 of the 11 expected result sets.");

                    ReadProductFeedbackBadgeAssociations(reader, feedbackCollection);
                    Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 2 of the 11 expected result sets.");

					ReadProductRatings(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 3 of the 11 expected result sets.");

					ReadProductRatingAttributeValues(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 4 of the 11 expected result sets.");

					ReadProductRecommendations(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 5 of the 11 expected result sets.");

					ReadProductRecommendationAttributeValues(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 6 of the 11 expected result sets.");

					ReadProductReviews(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 7 of the 11 expected result sets.");

					ReadProductReviewAttributeValues(reader, feedbackCollection);
					Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 8 of the 11 expected result sets.");

                    ReadProductReviewImages(reader, feedbackCollection);
                    Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 9 of the 11 expected result sets.");

                    ReadProductReviewVideos(reader, feedbackCollection);
                    Safety.AssertTrue(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned only 10 of the 11 expected result sets.");

                    ReadProductReviewThirdPartyRatingCounts(reader, feedbackCollection);
					Safety.AssertFalse(reader.NextResult(), StoredProcedure.GetProductFeedback.CommandName + " returned more than the 11 expected result sets.");
				}
				finally
				{
					reader.Close();
				}
			}
			return feedbackCollection;
		}

		private static void ReadProductFeedback(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
		    ProductFeedbackE feedback;

		    Safety.AssertArgumentNotNull("reader", reader);
		    Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

		    while (reader.Read())
		    {
		        feedback = ReadProductFeedback(reader);
		        feedbackCollection.Add(feedback.FeedbackId, feedback);
		    }
		}

		private static ProductFeedbackE ReadProductFeedback(IDataReader reader)
		{
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);

			feedback = new ProductFeedbackE();
			feedback.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			feedback.CultureId = (int)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CultureId];
			feedback.DateAdded = (DateTime)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.DateAdded];
			feedback.CustomerId = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerId] as Guid?;
			feedback.CustomerName = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerName];
			feedback.CustomerLocation = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.CustomerLocation] as string;
			feedback.EditorComments = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.EditorComments] as string;
			return feedback;
		}

        private static void ReadProductFeedbackBadgeAssociations(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
        {
            ProductFeedbackBadgeAssociation badgeAssociation;
            ProductFeedbackE feedback;

            Safety.AssertArgumentNotNull("reader", reader);
            Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

            while (reader.Read())
            {
                badgeAssociation = ReadProductFeedbackBadgeAssociation(reader);
                feedback = feedbackCollection[badgeAssociation.FeedbackId];
                feedback.BadgeAssociations.Add(badgeAssociation.BadgeId, badgeAssociation);
            }
        }

        private static ProductFeedbackBadgeAssociation ReadProductFeedbackBadgeAssociation(IDataReader reader)
        {
            ProductFeedbackBadgeAssociation FeedbackBadgeAssociation;

            Safety.AssertArgumentNotNull("reader", reader);

            FeedbackBadgeAssociation = new ProductFeedbackBadgeAssociation();
            FeedbackBadgeAssociation.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
            FeedbackBadgeAssociation.BadgeId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedbackBadgeAssociation.BadgeId];
            return FeedbackBadgeAssociation;
        }

        private static void ReadProductRatings(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductRating rating;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				rating = ReadProductRating(reader);
				feedback = feedbackCollection[rating.FeedbackId];
				feedback.Rating = rating;
			}
		}

		private static ProductRating ReadProductRating(IDataReader reader)
		{
			ProductRating rating;

			Safety.AssertArgumentNotNull("reader", reader);

			rating = new ProductRating();
			rating.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			rating.Value = (byte)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRating.Value];
			return rating;
		}

		private static void ReadProductRatingAttributeValues(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductRatingAttributeValue attributeValue;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				attributeValue = ReadProductRatingAttributeValue(reader);
				feedback = feedbackCollection[attributeValue.FeedbackId];
                Safety.AssertNotNull(feedback.Rating, "ReadProductRatingAttributeValues called for feedback without a rating component.");
				feedback.Rating.AttributeValues.Add(attributeValue.AttributeId, attributeValue);
			}
		}

		private static ProductRatingAttributeValue ReadProductRatingAttributeValue(IDataReader reader)
		{
			ProductRatingAttributeValue attributeValue;

			Safety.AssertArgumentNotNull("reader", reader);

			attributeValue = new ProductRatingAttributeValue();
			attributeValue.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			attributeValue.AttributeId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRatingAttributeValue.AttributeId];
			attributeValue.Value = (byte)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRatingAttributeValue.Value];
			return attributeValue;
		}

		private static void ReadProductRecommendations(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductRecommendation recommendation;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				recommendation = ReadProductRecommendation(reader);
				feedback = feedbackCollection[recommendation.FeedbackId];
				feedback.Recommendation = recommendation;
			}
		}

		private static ProductRecommendation ReadProductRecommendation(IDataReader reader)
		{
			ProductRecommendation recommendation;

			Safety.AssertArgumentNotNull("reader", reader);

			recommendation = new ProductRecommendation();
			recommendation.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			recommendation.Value = (bool)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendation.Value];
			return recommendation;
		}

		private static void ReadProductRecommendationAttributeValues(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductRecommendationAttributeValue attributeValue;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				attributeValue = ReadProductRecommendationAttributeValue(reader);
				feedback = feedbackCollection[attributeValue.FeedbackId];
                Safety.AssertNotNull(feedback.Recommendation, "ReadProductRecommendationAttributeValues called for feedback without a recommendation component."); 
                feedback.Recommendation.AttributeValues.Add(attributeValue.AttributeId, attributeValue);
			}
		}

		private static ProductRecommendationAttributeValue ReadProductRecommendationAttributeValue(IDataReader reader)
		{
			ProductRecommendationAttributeValue attributeValue;

			Safety.AssertArgumentNotNull("reader", reader);

			attributeValue = new ProductRecommendationAttributeValue();
			attributeValue.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			attributeValue.AttributeId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendationAttributeValue.AttributeId];
			attributeValue.Value = (bool)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductRecommendationAttributeValue.Value];
			return attributeValue;
		}

		private static void ReadProductReviews(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductReview review;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				review = ReadProductReview(reader);
				feedback = feedbackCollection[review.FeedbackId];
				feedback.Review = review;
			}
		}

		private static ProductReview ReadProductReview(IDataReader reader)
		{
			ProductReview review;

			Safety.AssertArgumentNotNull("reader", reader);

			review = new ProductReview();
			review.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			review.Title = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReview.Title] as string;
			review.Body = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReview.Body];
			return review;
		}

		private static void ReadProductReviewAttributeValues(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			ProductReviewAttributeValue attributeValue;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				attributeValue = ReadProductReviewAttributeValue(reader);
				feedback = feedbackCollection[attributeValue.FeedbackId];
                Safety.AssertNotNull(feedback.Rating, "ReadProductReviewAttributeValues called for feedback without a review component.");
                feedback.Review.AttributeValues.Add(attributeValue.AttributeId, attributeValue);
			}
		}

		private static ProductReviewAttributeValue ReadProductReviewAttributeValue(IDataReader reader)
		{
			ProductReviewAttributeValue attributeValue;

			Safety.AssertArgumentNotNull("reader", reader);

			attributeValue = new ProductReviewAttributeValue();
			attributeValue.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
			attributeValue.AttributeId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewAttributeValue.AttributeId];
			attributeValue.Value = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewAttributeValue.Value];
			return attributeValue;
		}

        private static void ReadProductReviewImages(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
        {
            ProductReviewImage image;
            ProductFeedbackE feedback;

            Safety.AssertArgumentNotNull("reader", reader);
            Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

            while (reader.Read())
            {
                image = ReadProductReviewImage(reader);
                feedback = feedbackCollection[image.FeedbackId];
                Safety.AssertNotNull(feedback.Rating, "ReadProductReviewImages called for feedback without a review component."); 
                feedback.Review.Images.Add(image.ImageId, image);
            }
        }

        private static ProductReviewImage ReadProductReviewImage(IDataReader reader)
        {
            ProductReviewImage image;

            Safety.AssertArgumentNotNull("reader", reader);

            image = new ProductReviewImage();
            image.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
            image.ImageId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageId];
            image.Caption = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.Caption] as string;
            image.ThumbnailPath = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailPath];
            image.ThumbnailWidth = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailWidth];
            image.ThumbnailHeight = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ThumbnailHeight];
            image.ImagePath = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImagePath];
            image.ImageWidth = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageWidth];
            image.ImageHeight = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewImage.ImageHeight];
            return image;
        }

        private static void ReadProductReviewVideos(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
        {
            ProductReviewVideo video;
            ProductFeedbackE feedback;

            Safety.AssertArgumentNotNull("reader", reader);
            Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

            while (reader.Read())
            {
                video = ReadProductReviewVideo(reader);
                feedback = feedbackCollection[video.FeedbackId];
                Safety.AssertNotNull(feedback.Rating, "ReadProductReviewVideos called for feedback without a review component.");
                feedback.Review.Video = video;
            }
        }

        private static ProductReviewVideo ReadProductReviewVideo(IDataReader reader)
        {
            ProductReviewVideo video;

            Safety.AssertArgumentNotNull("reader", reader);

            video = new ProductReviewVideo();
            video.FeedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
            video.StillPath = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillPath];
            video.StillWidth = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillWidth];
            video.StillHeight = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.StillHeight];
            video.VideoPath = (string)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoPath];
            video.VideoWidth = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoWidth];
            video.VideoHeight = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.VideoHeight];
            video.Length = (short)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.Length];
            video.Transcript = reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewVideo.Transcript] as string;
            return video;
        }

        private static void ReadProductReviewThirdPartyRatingCounts(IDataReader reader, Dictionary<Guid, ProductFeedbackE> feedbackCollection)
		{
			Guid feedbackId;
			int totalThirdPartyReviews;
			int positiveThirdPartyReviews;
			ProductFeedbackE feedback;

			Safety.AssertArgumentNotNull("reader", reader);
			Safety.AssertArgumentNotNull("feedbackCollection", feedbackCollection);

			while (reader.Read())
			{
				feedbackId = (Guid)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductFeedback.FeedbackId];
				totalThirdPartyReviews = (int)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewThirdPartyRatingCounts.TotalThirdPartyReviews];
				positiveThirdPartyReviews = (int)reader[StoredProcedure.GetProductFeedback.ColumnName.ProductReviewThirdPartyRatingCounts.PositiveThirdPartyReviews];

				feedback = feedbackCollection[feedbackId];
				feedback.Review.TotalThirdPartyReviews = totalThirdPartyReviews;
				feedback.Review.PositiveThirdPartyReviews = positiveThirdPartyReviews;
			}
		}

		#endregion // GetProductFeedback

		#endregion // Implementation

	}

}
